home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / think / AmigaGnuChess.lha / chess / src.lha / src / book.c < prev    next >
C/C++ Source or Header  |  1992-09-06  |  9KB  |  394 lines

  1. /*
  2.  * book.c - C source for GNU CHESS
  3.  *
  4.  * Copyright (c) 1988,1989,1990 John Stanback
  5.  * Copyright (c) 1992 Free Software Foundation
  6.  *
  7.  * This file is part of GNU CHESS.
  8.  *
  9.  * GNU Chess is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2, or (at your option)
  12.  * any later version.
  13.  *
  14.  * GNU Chess is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with GNU Chess; see the file COPYING.  If not, write to
  21.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  */
  23.  
  24. #include "gnuchess.h"
  25. extern char mvstr[4][6];
  26. int bookcount = 0;
  27. static struct bookentry
  28. {
  29.   unsigned long bookkey;
  30.   unsigned long bookbd;
  31.   unsigned short bmove;
  32.   unsigned short hint;
  33.   unsigned char count;
  34.   unsigned char flags;
  35. } *OpenBook;
  36. static struct bookentry *BookTable[BKTBLSIZE];
  37. void
  38. GetOpenings (void)
  39.  
  40. /*
  41.  * Read in the Opening Book file and parse the algebraic notation for a move
  42.  * into an unsigned integer format indicating the from and to square. Create
  43.  * a linked list of opening lines of play, with entry->next pointing to the
  44.  * next line and entry->move pointing to a chunk of memory containing the
  45.  * moves. More Opening lines of up to 100 half moves may be added to
  46.  * gnuchess.book.
  47.  * But now its a hashed table by position which yields a move or moves for 
  48.  * each position. It no longer knows about openings per say only positions
  49.  * and recommended moves in those positions.
  50.  */
  51. #ifndef BOOK
  52. #define BOOK "/usr/games/lib/gnuchess.book"
  53. #endif /* BOOK */
  54. {
  55.   FILE *fd;
  56.   register struct bookentry *OB, *OC;
  57.   register short int i, f, t;
  58.   char opening[80];
  59.   char msg[80];
  60.   short int xside, doit, c, side;
  61.   short int rf, rt;
  62.   unsigned short mv;
  63.   int bs;
  64.   unsigned long ltmp;
  65.   extern char *malloc();
  66. #ifdef AMIGA
  67.   char bookname[256];
  68. #endif
  69.  
  70.   /* allocate space for the book */
  71.   OpenBook = (struct bookentry *) malloc(BOOKSIZE*sizeof(struct bookentry));
  72.  
  73.   for (i = 0; i < BKTBLSIZE; i++)
  74.     {
  75.       BookTable[i] = &OpenBook[BOOKSIZE / BKTBLSIZE * i];
  76.     }
  77. #ifdef BINBOOK
  78.   fd = fopen (BINBOOK, "r");
  79.   if (fd != NULL)
  80.     {
  81.       fscanf(fd, "%d\n", &bs);
  82.       fscanf(fd, "%d\n", &bookcount);
  83.       if (bs == BOOKSIZE)
  84.     {
  85.       if(0>fread(OpenBook, sizeof(struct bookentry), BOOKSIZE, fd))
  86.         perror("fread");
  87.       /* set every thing back to start game */
  88.       Book = BOOKFAIL;
  89.       for (i = 0; i < 64; i++)
  90.         {
  91.           board[i] = Stboard[i];
  92.           color[i] = Stcolor[i];
  93.         }
  94.       fclose(fd);
  95.       return;
  96.       
  97.     }
  98.       fclose(fd);
  99.     }
  100. #endif
  101.  
  102.   for (OB = OpenBook; OB < &OpenBook[BOOKSIZE]; OB++)
  103.     OB->count = 0;
  104. #ifdef AMIGA
  105.   strcpy(bookname, libdir);
  106.   AddPart(bookname, FilePart(BOOK), 256);
  107.   if ((fd = fopen (bookname, "r")) == NULL)
  108.     fd = fopen ("gnuchess.book", "r");
  109. #else
  110.   if ((fd = fopen (BOOK, "r")) == NULL)
  111.     fd = fopen ("gnuchess.book", "r");
  112. #endif
  113.   if (fd != NULL)
  114.     {
  115.       OC = NULL;
  116.       /* setvbuf(fd,buffr,_IOFBF,2048); */
  117.       side = white;
  118.       xside = black;
  119.       hashbd = hashkey = 0;
  120.       for (i = 0; i < 64; i++)
  121.     {
  122.       board[i] = Stboard[i];
  123.       color[i] = Stcolor[i];
  124.     }
  125.       i = 0;
  126.  
  127.       while ((c = parse (fd, &mv, side, opening)) >= 0)
  128.     if (c == 1)
  129.       {
  130.  
  131.         /*
  132.          * if not first move of an opening and first time we have
  133.          * seen it save next move as hint
  134.          */
  135.         if (i && OB->count == 1)
  136.           OB->hint = mv & 0x3f3f;
  137.         OC = OB;        /* save for end marking */
  138.         doit = true;
  139.  
  140.         /*
  141.          * see if this position and move already exist from some
  142.          * other opening
  143.          */
  144.         /* is this ethical, to offer the bad move as a hint????? */
  145.         for (OB = BookTable[hashkey & BOOKMASK]; OB->count; OB++)
  146.           {
  147.         if (OB->bookkey == hashkey
  148.             && OB->bookbd == hashbd
  149.             && (OB->flags & SIDEMASK) == side
  150.             && OB->bmove == mv)
  151.           {
  152.             
  153.             /*
  154.              * yes so just bump count - count is used to choose
  155.              * opening move in proportion to its presence in the
  156.              * book
  157.              */
  158.             doit = false;
  159.             OB->count++;
  160.             if (OB->count < 1)
  161.               OB->count--;
  162.             break;
  163.           }
  164.         /* Book is hashed into BKTBLSIZE chunks based on hashkey */
  165.         if (OB == &OpenBook[BOOKSIZE - 1])
  166.           OB = OpenBook;
  167.           }
  168.         /* doesn`t exist so add it to the book */
  169.         if (doit)
  170.           {
  171.         bookcount++;
  172.         OB->bookkey = hashkey;
  173.         OB->bookbd = hashbd;
  174.         OB->bmove = mv;
  175.         OB->hint = 0;
  176.         OB->count = 1;
  177.         OB->flags = side;
  178.           }
  179.         /* now update the board and hash values */
  180.         /* should really check the moves as we do this, but??? */
  181.         f = mv >> 8 & 0x3F;
  182.         t = mv & 0x3F;
  183.         if (board[t] != no_piece)
  184.           {
  185.         if (color[t] != xside)
  186.           {
  187.             algbr (f, t, false);
  188.             sprintf (msg, CP[211], i + 1, mvstr, opening);
  189.             ShowMessage (msg);
  190.           }
  191.         UpdateHashbd (xside, board[t], -1, t);
  192.           }
  193.         if (board[f] == no_piece || color[f] != side)
  194.           {
  195.         algbr (f, t, false);
  196.         sprintf (msg, CP[211], i + 1, mvstr, opening);
  197.         ShowMessage (msg);
  198.           }
  199.         UpdateHashbd (side, board[f], f, t);
  200.         board[t] = board[f];
  201.         color[t] = color[f];
  202.         color[f] = neutral;
  203.         board[f] = no_piece;
  204.         if ((board[t] == king) && ((mv == BLACKCASTLE) || (mv == WHITECASTLE) || (mv == LONGBLACKCASTLE) || (mv == LONGWHITECASTLE)))
  205.           {
  206.  
  207.         if (t > f)
  208.           {
  209.             rf = f + 3;
  210.             rt = t - 1;
  211.           }
  212.         else
  213.           {
  214.             rf = f - 4;
  215.             rt = t + 1;
  216.           }
  217.         board[rt] = rook;
  218.         color[rt] = side;
  219.         board[rf] = no_piece;
  220.         color[rf] = neutral;
  221.         UpdateHashbd (side, rook, rf, rt);
  222.           }
  223.         i++;
  224.         xside = side;
  225.         side = side ^ 1;
  226.       }
  227.     else if (c == 0 && i > 0)
  228.       {
  229.         /* Mark last move as end of an opening */
  230.         /* might want to terminate? */
  231.         OB->flags |= BOOKEND;
  232.         if (i > 1)
  233.           OC->flags |= BOOKEND;
  234.         /* reset for next opening */
  235.         side = white;
  236.         hashbd = hashkey = 0;
  237.         for (i = 0; i < 64; i++)
  238.           {
  239.         board[i] = Stboard[i];
  240.         color[i] = Stcolor[i];
  241.           }
  242.         i = 0;
  243.  
  244.       }
  245.       fclose (fd);
  246. #ifdef BINBOOK
  247.       fd = fopen (BINBOOK, "w");
  248.       fprintf(fd, "%d\n%d\n", BOOKSIZE, bookcount);
  249.       if(0>fwrite(OpenBook, sizeof(struct bookentry), BOOKSIZE, fd))
  250.     perror("fwrite");
  251.       fclose (fd);
  252. #endif
  253. #if !defined CHESSTOOL && !defined XBOARD
  254.       sprintf (msg, CP[213], bookcount, BOOKSIZE);
  255.       ShowMessage (msg);
  256. #endif
  257.       /* set every thing back to start game */
  258.       Book = BOOKFAIL;
  259.       for (i = 0; i < 64; i++)
  260.     {
  261.       board[i] = Stboard[i];
  262.       color[i] = Stcolor[i];
  263.     }
  264.     }
  265.   else
  266.     {
  267. #if !defined CHESSTOOL && !defined XBOARD
  268.       ShowMessage (CP[212]);
  269. #endif
  270.       Book = 0;
  271.     }
  272. }
  273.  
  274.  
  275. int
  276. OpeningBook (unsigned short *hint, short int side)
  277.      
  278. /*
  279.  * Go thru each of the opening lines of play and check for a match with the
  280.  * current game listing. If a match occurs, generate a random number. If this
  281.  * number is the largest generated so far then the next move in this line
  282.  * becomes the current "candidate". After all lines are checked, the
  283.  * candidate move is put at the top of the Tree[] array and will be played by
  284.  * the program. Note that the program does not handle book transpositions.
  285.  */
  286.  
  287. {
  288.   short pnt;
  289.   unsigned short m;
  290.   unsigned r, cnt, tcnt, ccnt;
  291.   register struct bookentry *OB, *OC;
  292.   int possibles = TrPnt[2] - TrPnt[1];
  293.  
  294.   srand ((unsigned int) time ((long *) 0));
  295.   m = 0;
  296.   cnt = 0;
  297.   tcnt = 0;
  298.   ccnt = 0;
  299.   OC = NULL;
  300.   
  301.  
  302.   /*
  303.    * find all the moves for this position  - count them and get their total
  304.    * count
  305.    */
  306.   for (OB = BookTable[hashkey & BOOKMASK]; OB->count; OB++)
  307.     {
  308.       if (OB->bookkey == hashkey
  309.       && OB->bookbd == hashbd
  310.       && ((OB->flags) & SIDEMASK) == side)
  311.     {
  312.       if (OB->bmove & BADMOVE)
  313.         {
  314.           m = OB->bmove ^ BADMOVE;
  315.           /* is the move is in the MoveList */
  316.           for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  317.         {
  318.           if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  319.             {
  320.               if (--possibles)
  321.             {
  322.               Tree[pnt].score = DONTUSE;
  323.               break;
  324.             }
  325.             }
  326.         }
  327.  
  328.         }
  329.       else
  330.         {
  331.           OC = OB;
  332.           cnt++;
  333.           tcnt += OB->count;
  334.         }
  335.     }
  336.     }
  337.   /* if only one just do it */
  338.   if (cnt == 1)
  339.     {
  340.       m = OC->bmove;
  341.     }
  342.   else
  343.     /* more than one must choose one at random */
  344.   if (cnt > 1)
  345.     {
  346.       /* pick a number */
  347.       r = urand () % 1000;
  348.  
  349.       for (OC = BookTable[hashkey & BOOKMASK]; OC->count; OC++)
  350.     {
  351.       if (OC->bookkey == hashkey
  352.           && OC->bookbd == hashbd
  353.           && ((OC->flags) & SIDEMASK) == side
  354.           && !(OC->bmove & BADMOVE))
  355.         {
  356.           ccnt += OC->count;
  357.           if (((ccnt * BOOKRAND) / tcnt) >= r)
  358.         {
  359.           m = OC->bmove;
  360.           break;
  361.         }
  362.         }
  363.     }
  364.     }
  365.   else
  366.     {
  367.       /* none decrement count of no finds */
  368.       Book--;
  369.       return false;
  370.     }
  371.   /* make sure the move is in the MoveList */
  372.   for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  373.     {
  374.       if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  375.     {
  376.       Tree[pnt].score = 0;
  377.       break;
  378.     }
  379.     }
  380.   /* Make sure its the best */
  381.  
  382.   pick (TrPnt[1], TrPnt[2] - 1);
  383.   if (Tree[TrPnt[1]].score)
  384.     {
  385.       /* no! */
  386.       Book--;
  387.       return false;
  388.     }
  389.   /* ok pick up the hint and go */
  390.   *hint = OC->hint;
  391.   Book = ((OC->flags & BOOKEND) && ((urand () % 1000) > BOOKENDPCT)) ? 0 : BOOKFAIL;
  392.   return true;
  393. }
  394.